package pl.ps.wi.monitoring.station.services;

import java.io.IOException;
import java.io.OutputStream;

import com.ftdichip.ftd2xx.BitBangMode;
import com.ftdichip.ftd2xx.Device;
import com.ftdichip.ftd2xx.FTD2xxException;
import com.ftdichip.ftd2xx.Service;

/**
* @brief Zawiera klasę DoorLock. Implementuje interfejs Runnable. Zawiera metodę main przeznaczoną dla celów testowych.
* 
* @date 22.03.2010
* @version 1.0
 */
 /**
  * Klasa DoorLock implementująca interfejs Runnable. Klasa obsługuje zamykanie i otwieranie rygla. \n
  * Posiada następujące pola: 
*- DoorLock::time 
*- DoorLock::message 
*- DoorLock::deviceByDesc
*- DoorLock::thread thread
* Oraz następujące metody: DoorLock::DoorLock
  */
public class DoorLock implements Runnable {
	
	
	// how long doors will stay open
	/**
	* Pole typu int time. 
	* Określa czas jak długo drzwi będa otwarte.
	*/
	private final int time;
	
	
	// message[1] - open doors
	// message[0] - close doors
	/**
	 * Tablica byte'ów message. Wartości message[1] - open doors, message[0] - close doors.
	 */
	private final byte[] message={(byte)0,(byte)255};
	
	// all devices in the system
	/**
	 * Tablica obiektów Device deviceByDesc. Wszystkie obiekty w systemie.
	 */
	private final Device[] devicesByDesc;
	/**
	 * Pole obiektu typu Thread thread. Pole obsługujące usługi związane z wątkami w systemie.
	 */
	private Thread thread;
	
	
	// default constructor , time value is set on 5 sec by default
	/**
	 * Standardowy konstruktor klsay. Wywołuje przeladowany konstruktor z czasem 5 sekund.
	 * @throws IOException
	 */
	public DoorLock() throws IOException {
		this(5000);
	}

	// overloaded constructor , time as an argument
	/**
	 * Przeładowany konstruktor klasy. Jako parametr przyjmuje czas przez jaki drzwi mają być otwarte.
	 "piotrkow" to opis rygla zaszyty w sprzęcie.
	 * @param t czas
	 * @see time
	 * @see devicesByDesc
	 * @see message
	 * @throws IOException
	 */
	public DoorLock(int t) throws IOException{
		thread=new Thread(this);
		
		time=t;
		devicesByDesc = Service.listDevicesByDescription("piotrkow");

		for(int i=0;i<devicesByDesc.length;i++){
			
			Device device=devicesByDesc[i];
	
			// opening device in asynchronous mode.
			device.open();
			device.setBitBangMode(0xFF,BitBangMode.ASYNCHRONOUS);
	
			OutputStream os=device.getOutputStream();			
			
			os.write(message[0]);
			device.close();
		}
	}
	/**
	 * Metoda otwierająca zamek, działająca jako osobny wątek. Otwiera zamek na określony w konstruktorze czas w trybie asynchronicznym.
	 * @see time
	 * @see devicesByDesc
	 * @see message 
	 */
	public void  run(){
	
	try {
			
		for(int i=0;i<devicesByDesc.length;i++){
			
				Device device=devicesByDesc[i];
				// opening device in asynchronous mode.
				device.open();
				device.setBitBangMode(0xFF,BitBangMode.ASYNCHRONOUS);
		
				OutputStream os=device.getOutputStream();
				
				os.write(message[1]);
				
				Thread.sleep(time);
				os.write(message[0]);
				device.close();
			}
	
		} catch (FTD2xxException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}
	/**
	 * Metoda open. Uruchamia wątek.
	 * @throws IOException
	 * @see thread
	 */
	
	synchronized public void open() throws IOException{
		thread=new Thread(this);
		thread.start();
		
	}
	/**
	 * Przeładowana metoda open. Uruchamia wątek z określonym czasem.
	 * @throws IOException
	 * @see thread
	 * @see time
	 * @throws IOException
	 */
	synchronized public void open(int time) throws IOException{
		thread=new Thread(this);
		thread.start();
		
	}

	/**
	 * Metoda main. Tworzy nowy obiekt DoorLock i uruchamia go do działania.
	 * @param args
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static void main(String[] args) throws IOException, InterruptedException{	
		
		DoorLock r=new DoorLock();
		
		Thread.sleep(10000);
		
		r.open();
		
	}
}
